<?php

namespace app\common\library;

/**
 * Session 错误处理类
 * 处理 session 权限错误，自动重定向到登录页面
 */
class SessionHandler
{
    /**
     * 检查并处理 session 错误
     * @return void
     */
    public static function checkSessionError()
    {
        // 设置错误处理器
        set_error_handler([self::class, 'sessionErrorHandler'], E_WARNING);
        
        // 检查最后的错误
        $error = error_get_last();
        if ($error && self::isSessionError($error)) {
            self::handleSessionError();
        }
        
        // 检查 session 状态
        if (!self::isSessionValid()) {
            self::handleSessionError();
        }
    }
    
    /**
     * Session 错误处理器
     * @param int $errno 错误级别
     * @param string $errstr 错误信息
     * @param string $errfile 错误文件
     * @param int $errline 错误行号
     * @return bool
     */
    public static function sessionErrorHandler($errno, $errstr, $errfile, $errline)
    {
        // 检查是否是 session 相关错误
        if (strpos($errstr, 'session_start()') !== false || 
            strpos($errstr, 'Permission denied') !== false ||
            strpos($errstr, 'sess_') !== false) {
            
            self::handleSessionError();
            return true;
        }
        
        // 其他错误继续正常处理
        return false;
    }
    
    /**
     * 判断是否是 session 错误
     * @param array $error 错误信息
     * @return bool
     */
    private static function isSessionError($error)
    {
        if (!$error) {
            return false;
        }
        
        $sessionErrors = [
            'session_start()',
            'Permission denied',
            'sess_',
            'Failed to read session data',
            'Failed to write session data'
        ];
        
        foreach ($sessionErrors as $errorPattern) {
            if (strpos($error['message'], $errorPattern) !== false) {
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * 检查 session 是否有效
     * @return bool
     */
    private static function isSessionValid()
    {
        try {
            // 尝试启动 session
            if (session_status() === PHP_SESSION_NONE) {
                @session_start();
            }
            return true;
        } catch (Exception $e) {
            return false;
        }
    }
    
    /**
     * 处理 session 错误
     * @return void
     */
    public static function handleSessionError()
    {
        try {
            // 清理 session
            self::cleanSession();
            
            // 记录错误日志
            self::logSessionError();
            
            // 重定向到登录页面
            self::redirectToLogin();
            
        } catch (Exception $e) {
            // 如果处理失败，强制重定向
            self::forceRedirectToLogin();
        }
    }
    
    /**
     * 清理 session
     * @return void
     */
    private static function cleanSession()
    {
        try {
            // 销毁 session
            if (session_status() === PHP_SESSION_ACTIVE) {
                session_destroy();
            }
            
            // 清理 session cookie
            $sessionName = session_name();
            if (isset($_COOKIE[$sessionName])) {
                setcookie($sessionName, '', time() - 3600, '/');
                unset($_COOKIE[$sessionName]);
            }
            
            // 清理 $_SESSION 变量
            $_SESSION = [];
            
        } catch (Exception $e) {
            // 忽略清理错误
        }
    }
    
    /**
     * 记录 session 错误日志
     * @return void
     */
    private static function logSessionError()
    {
        try {
            $logFile = RUNTIME_PATH . 'log/session_error.log';
            $logDir = dirname($logFile);
            
            // 确保日志目录存在
            if (!is_dir($logDir)) {
                mkdir($logDir, 0755, true);
            }
            
            $logMessage = date('Y-m-d H:i:s') . " - Session Error: " . 
                         "IP: " . ($_SERVER['REMOTE_ADDR'] ?? 'unknown') . 
                         ", User-Agent: " . ($_SERVER['HTTP_USER_AGENT'] ?? 'unknown') . 
                         ", URL: " . ($_SERVER['REQUEST_URI'] ?? 'unknown') . "\n";
            
            file_put_contents($logFile, $logMessage, FILE_APPEND | LOCK_EX);
            
        } catch (Exception $e) {
            // 忽略日志错误
        }
    }
    
    /**
     * 重定向到登录页面
     * @return void
     */
    private static function redirectToLogin()
    {
        // 检查是否是 AJAX 请求
        if (self::isAjaxRequest()) {
            self::ajaxResponse();
        } else {
            self::httpRedirect();
        }
    }
    
    /**
     * 判断是否是 AJAX 请求
     * @return bool
     */
    private static function isAjaxRequest()
    {
        return !empty($_SERVER['HTTP_X_REQUESTED_WITH']) && 
               strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';
    }
    
    /**
     * AJAX 响应
     * @return void
     */
    private static function ajaxResponse()
    {
        header('Content-Type: application/json; charset=utf-8');
        echo json_encode([
            'code' => 0,
            'msg' => 'Session已过期，请重新登录',
            'url' => '/admin/index/login',
            'data' => null
        ], JSON_UNESCAPED_UNICODE);
        exit;
    }
    
    /**
     * HTTP 重定向
     * @return void
     */
    private static function httpRedirect()
    {
        header('Location: /admin/index/login');
        exit;
    }
    
    /**
     * 强制重定向（当其他方法失败时）
     * @return void
     */
    private static function forceRedirectToLogin()
    {
        echo '<script>window.location.href="/admin/index/login";</script>';
        echo '<meta http-equiv="refresh" content="0;url=/admin/index/login">';
        exit;
    }
    
    /**
     * 初始化 session 处理
     * 在应用启动时调用
     * @return void
     */
    public static function init()
    {
        // 设置全局错误处理器
        set_error_handler([self::class, 'sessionErrorHandler'], E_WARNING);
        
        // 设置 session 错误处理
        register_shutdown_function([self::class, 'shutdownHandler']);
    }
    
    /**
     * 关闭处理器
     * @return void
     */
    public static function shutdownHandler()
    {
        $error = error_get_last();
        if ($error && self::isSessionError($error)) {
            self::handleSessionError();
        }
    }
}
